﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using System.IO;
using QLab.UX.Engine;
using QLab.UX.Utilities;

namespace QLab.UX.Forms
{
    public partial class SolutionExplorerWindow : ToolWindow
    {
        #region ToolStripItems
        private ToolStripMenuItem slnNewProjectMenuItem;

        private ToolStripMenuItem prjNewFolderMenuItem;
        private ToolStripMenuItem prjNewFileMenuItem;
        private ToolStripMenuItem prjDeleteMenuItem;
        private ToolStripMenuItem prjRemoveFromSlnMenuItem;
        private ToolStripMenuItem prjSetActive;

        private ToolStripMenuItem folderNewFolderMenuItem;
        private ToolStripMenuItem folderNewFileMenuItem;
        private ToolStripMenuItem folderDeleteMenuItem;
        private ToolStripMenuItem folderSetActive;

        private ToolStripMenuItem fileDeleteMenuItem;
        #endregion

        private TreeNode selectedNode = null;
        private TreeNode activeNode = null;

        public SolutionExplorerWindow(ToolStripMenuItem toolStripMenuItem, DockPanel dockPanel)
            : base("Solution Explorer", EnumsEngine.GetToolWindowName(ToolWindowType.SolutionExplorer), toolStripMenuItem, dockPanel)
        {
            InitializeComponent();

            InitializeComponentQLab();
        }

        private void InitializeComponentQLab()
        {
            this.slnNewProjectMenuItem = new ToolStripMenuItem("New Project...");

            this.prjNewFolderMenuItem = new ToolStripMenuItem("New Folder...");
            this.prjNewFileMenuItem = new ToolStripMenuItem("New File...");
            this.prjDeleteMenuItem = new ToolStripMenuItem("Delete");
            this.prjRemoveFromSlnMenuItem = new ToolStripMenuItem("Remove From Solution");
            this.prjSetActive = new ToolStripMenuItem("Set Active");

            this.folderNewFolderMenuItem = new ToolStripMenuItem("New Folder...");
            this.folderNewFileMenuItem = new ToolStripMenuItem("New File...");
            this.folderDeleteMenuItem = new ToolStripMenuItem("Delete");
            this.folderSetActive = new ToolStripMenuItem("Set Active");

            this.fileDeleteMenuItem = new ToolStripMenuItem("Delete");

            this.slnNewProjectMenuItem.Click += new EventHandler(slnNewProjectMenuItem_Click);

            this.prjNewFolderMenuItem.Click += new EventHandler(prjNewFolderMenuItem_Click);
            this.prjNewFileMenuItem.Click += new EventHandler(prjNewFileMenuItem_Click);
            this.prjDeleteMenuItem.Click += new EventHandler(prjDeleteMenuItem_Click);
            this.prjRemoveFromSlnMenuItem.Click += new EventHandler(prjRemoveFromSlnMenuItem_Click);
            this.prjSetActive.Click += new EventHandler(prjSetActive_Click);

            this.folderNewFileMenuItem.Click += new EventHandler(folderNewFileMenuItem_Click);
            this.folderNewFolderMenuItem.Click += new EventHandler(folderNewFolderMenuItem_Click);
            this.folderDeleteMenuItem.Click += new EventHandler(folderDeleteMenuItem_Click);
            this.folderSetActive.Click += new EventHandler(folderSetActive_Click);

            this.fileDeleteMenuItem.Click += new EventHandler(fileDeleteMenuItem_Click);
        }        

        #region ToolStripEvents
        void fileDeleteMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabFunction)
            {
                QLabFunction file = this.selectedNode.Tag as QLabFunction;
                File.Delete(file.Path);
                file.ParentFolder.QLabFiles.Remove(file.Name);
                SolutionManager.Instance.SaveSolution();
                this.selectedNode.Remove();
            }
            this.selectedNode = null;
        }

        void folderDeleteMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabFolder)
            {
                QLabFolder folder = this.selectedNode.Tag as QLabFolder;
                Directory.Delete(folder.Path, true);
                folder.ParentFolder.QLabFolders.Remove(folder.Name);
                SolutionManager.Instance.SaveSolution();
                this.selectedNode.Remove();
            }
            this.selectedNode = null;
        }
        void folderNewFolderMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabFolder)
            {
                TextBoxForm form = new TextBoxForm("New Folder...", string.Empty);
                form.Location = Control.MousePosition;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    string text = form.NewText;
                    QLabFolder folder = this.selectedNode.Tag as QLabFolder;
                    if (PathHelper.Instance.IsRegularFileName(text) && !folder.QLabFolders.ContainsKey(text))
                    {
                        Directory.CreateDirectory(folder.Path + text + "\\");
                        QLabFolder newFolder = new QLabFolder(folder, folder.ParentProject, text, false);
                        folder.QLabFolders.Add(newFolder.Name, newFolder);
                        SolutionManager.Instance.SaveSolution();
                        TreeNode node = this.selectedNode.Nodes.Add(newFolder.Name);
                        node.ImageKey = "Folder.png";
                        node.SelectedImageKey = "Folder.png";
                        node.Tag = newFolder;
                        this.selectedNode.Expand();
                    }
                }
            }
        }
        void folderNewFileMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabFolder)
            {
                TextBoxForm form = new TextBoxForm("New File...", string.Empty);
                form.Location = Control.MousePosition;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    string text = form.NewText;
                    if (!text.EndsWith(".f"))
                        text += ".f";
                    QLabFolder folder = this.selectedNode.Tag as QLabFolder;
                    if (PathHelper.Instance.IsRegularFileName(text) && !folder.QLabFiles.ContainsKey(text))
                    {
                        File.Create(folder.Path + text).Close();
                        QLabFunction newFile = new QLabFunction(folder, folder.ParentProject, text);
                        folder.QLabFiles.Add(newFile.Name, newFile);
                        SolutionManager.Instance.SaveSolution();
                        TreeNode node = this.selectedNode.Nodes.Add(newFile.Name);
                        node.ImageKey = "Function.png";
                        node.SelectedImageKey = "Function.png";
                        node.Tag = newFile;
                        this.selectedNode.Expand();
                    }
                }
            }
        }
        void folderSetActive_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabFolder)
            {
                QLabFolder folder = selectedNode.Tag as QLabFolder;
                folder.Active = true;

                SolutionManager.Instance.ActiveFolder.Active = false;
                SolutionManager.Instance.ActiveFolder = folder;
                
                this.RefreshActive(this.selectedNode);
            }
        }

        void prjRemoveFromSlnMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabProject)
            {
                QLabProject project = this.selectedNode.Tag as QLabProject;
                project.ParentSolution.Projects.Remove(project.Name);
                SolutionManager.Instance.SaveSolution();
                this.selectedNode.Remove();
            }
            this.selectedNode = null;
        }
        void prjDeleteMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabProject)
            {
                QLabProject project = this.selectedNode.Tag as QLabProject;
                Directory.Delete(project.Folder.Path, true);
                project.ParentSolution.Projects.Remove(project.Name);
                SolutionManager.Instance.SaveSolution();
                this.selectedNode.Remove();
            }
            this.selectedNode = null;
        }
        void prjNewFileMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabProject)
            {
                TextBoxForm form = new TextBoxForm("New File...", string.Empty);
                form.Location = Control.MousePosition;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    string text = form.NewText;
                    if (!text.EndsWith(".f"))
                        text += ".f";
                    QLabProject project = this.selectedNode.Tag as QLabProject;
                    if (PathHelper.Instance.IsRegularFileName(text) && !project.Folder.QLabFiles.ContainsKey(text))
                    {
                        File.Create(project.Folder.Path + text).Close();
                        QLabFunction newFile = new QLabFunction(project.Folder, project, text);
                        project.Folder.QLabFiles.Add(newFile.Name, newFile);
                        SolutionManager.Instance.SaveSolution();
                        TreeNode node = this.selectedNode.Nodes.Add(newFile.Name);
                        node.ImageKey = "Function.png";
                        node.SelectedImageKey = "Function.png";
                        node.Tag = newFile;
                        this.selectedNode.Expand();
                    }
                }
            }
        }
        void prjNewFolderMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabProject)
            {
                TextBoxForm form = new TextBoxForm("New Folder...", string.Empty);
                form.Location = Control.MousePosition;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    string text = form.NewText;
                    QLabProject project = this.selectedNode.Tag as QLabProject;
                    if (PathHelper.Instance.IsRegularFileName(text) && !project.Folder.QLabFolders.ContainsKey(text))
                    {
                        Directory.CreateDirectory(project.Folder.Path + text + "\\");
                        QLabFolder newFolder = new QLabFolder(project.Folder, project, text, false);
                        project.Folder.QLabFolders.Add(newFolder.Name, newFolder);
                        SolutionManager.Instance.SaveSolution();
                        TreeNode node = this.selectedNode.Nodes.Add(newFolder.Name);
                        node.ImageKey = "Folder.png";
                        node.SelectedImageKey = "Folder.png";
                        node.Tag = newFolder;
                        this.selectedNode.Expand();
                    }
                }
            }
        }
        void prjSetActive_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabProject)
            {
                QLabProject project = selectedNode.Tag as QLabProject;
                project.Folder.Active = true;

                SolutionManager.Instance.ActiveFolder.Active = false;
                SolutionManager.Instance.ActiveFolder = project.Folder;

                this.RefreshActive(this.selectedNode);
            }
        }

        void slnNewProjectMenuItem_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null && selectedNode.Tag is QLabSolution)
            {
                TextBoxForm form = new TextBoxForm("New Project...", string.Empty);
                form.Location = Control.MousePosition;
                if (form.ShowDialog() == DialogResult.OK)
                {
                    string text = form.NewText;
                    QLabSolution solution = this.selectedNode.Tag as QLabSolution;
                    if (PathHelper.Instance.IsRegularFileName(text) && !solution.Projects.ContainsKey(text))
                    {
                        string absolutePath = solution.HomeFolderPath + text + "\\";


                        QLabProject newProject = new QLabProject(solution.HomeFolderPath + text + "\\", text, solution, false);
                        solution.Projects.Add(newProject.Name, newProject);
                        SolutionManager.Instance.SaveSolution();
                        TreeNode node = this.selectedNode.Nodes.Add(newProject.Name);
                        node.ImageKey = "Project.png";
                        node.SelectedImageKey = "Project.png";
                        node.Tag = newProject;
                        this.selectedNode.Expand();
                    }
                }
            }
        }
        #endregion

        protected override string GetPersistString()
        {
            return EnumsEngine.GetToolWindowName(ToolWindowType.SolutionExplorer);
        }

        public void Reload()
        {
            this.treeViewSolution.Nodes.Clear();
            QLabSolution sln = SolutionManager.Instance.ActiveSolution;

            if (sln == null)
            {
                this.treeViewSolution.Nodes.Clear();
                return;
            }
            TreeNode slnNode = this.treeViewSolution.Nodes.Add(sln.Name);
            slnNode.ImageKey = "Solution.png";
            slnNode.SelectedImageKey = "Solution.png";
            slnNode.Tag = sln;

            foreach (QLabProject prj in sln.Projects.Values)
            {
                TreeNode prjNode = slnNode.Nodes.Add(prj.Name);
                prjNode.ImageKey = "Project.png";
                prjNode.SelectedImageKey = "Project.png";
                prjNode.Tag = prj;

                if (prj.Folder.Active)
                {
                    prjNode.NodeFont = new Font(TreeView.DefaultFont, FontStyle.Bold);
                    this.activeNode = prjNode;
                }

                this.WriteFolderToNode(prj.Folder, prjNode);
            }

            slnNode.Expand();
        }

        private void RefreshActive(TreeNode newActiveNode)
        {
            this.activeNode.NodeFont = new Font(TreeView.DefaultFont, FontStyle.Regular);
            newActiveNode.NodeFont = new Font(TreeView.DefaultFont, FontStyle.Bold);
            this.activeNode = newActiveNode;
        }


        private void WriteFolderToNode(QLabFolder qLabFolder, TreeNode node)
        {
            foreach (QLabFolder folder in qLabFolder.QLabFolders.Values)
            {
                TreeNode folderNode = node.Nodes.Add(folder.Name);
                folderNode.ImageKey = "Folder.png";
                folderNode.SelectedImageKey = "Folder.png";
                folderNode.Tag = folder;

                if (folder.Active)
                {
                    folderNode.NodeFont = new Font(TreeView.DefaultFont, FontStyle.Bold);
                    this.activeNode = folderNode;
                }

                WriteFolderToNode(folder, folderNode);
            }

            foreach (QLabFunction file in qLabFolder.QLabFiles.Values)
            {
                TreeNode fileNode = node.Nodes.Add(file.Name);
                fileNode.ImageKey = "Function.png";
                fileNode.SelectedImageKey = "Function.png";
                fileNode.Tag = file;
            }
        }

        private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            if (this.treeViewSolution.SelectedNode == null)
            {
                e.Cancel = true;
                return;
            }

            this.selectedNode = treeViewSolution.SelectedNode;

            this.contextMenuStrip.Items.Clear();
            if (this.treeViewSolution.SelectedNode.Tag is QLabSolution)
            {
                this.contextMenuStrip.Items.Add(slnNewProjectMenuItem);
            }
            else if (this.treeViewSolution.SelectedNode.Tag is QLabProject)
            {
                this.contextMenuStrip.Items.Add(prjNewFolderMenuItem);
                this.contextMenuStrip.Items.Add(prjNewFileMenuItem);
                this.contextMenuStrip.Items.Add(prjDeleteMenuItem);
                this.contextMenuStrip.Items.Add(prjRemoveFromSlnMenuItem);
                this.contextMenuStrip.Items.Add(prjSetActive);
            }
            else if (this.treeViewSolution.SelectedNode.Tag is QLabFolder)
            {
                this.contextMenuStrip.Items.Add(folderNewFolderMenuItem);
                this.contextMenuStrip.Items.Add(folderNewFileMenuItem);
                this.contextMenuStrip.Items.Add(folderDeleteMenuItem);
                this.contextMenuStrip.Items.Add(folderSetActive);
            }
            else if (this.treeViewSolution.SelectedNode.Tag is QLabFunction)
            {
                this.contextMenuStrip.Items.Add(fileDeleteMenuItem);
            }
        }

        private void treeViewSolution_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            if (e.Node.Tag is QLabSolution)
            {
                QLabSolution sln = e.Node.Tag as QLabSolution;
                e.Node.Text = sln.Name;
            }
        }

        private void treeViewSolution_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            if (e.Label == null)
            {
                e.CancelEdit = true;
                return;
            }
            string text = e.Label;
            if (e.Node.Tag is QLabSolution)
            {
                #region Edit Solution Name
                if (!PathHelper.Instance.IsRegularFileName(text))
                {
                    e.CancelEdit = true;
                    return;
                }

                QLabSolution sln = e.Node.Tag as QLabSolution;
                if (text == sln.Name) return;
                File.Move(sln.HomeFolderPath + sln.File, sln.HomeFolderPath + text + ".qlsln");
                sln.Name = text;
                SolutionManager.Instance.SaveSolution();
                #endregion
            }
            else if (e.Node.Tag is QLabProject)
            {
                #region Edit Project Name
                if (!PathHelper.Instance.IsRegularFileName(text))
                {
                    e.CancelEdit = true;
                    e.Node.Text = (e.Node.Tag as QLabProject).Name;
                    return;
                }

                QLabProject prj = e.Node.Tag as QLabProject;
                if (text == prj.Name || prj.ParentSolution.Projects.ContainsKey(text)) return;

                File.Move(prj.Folder.Path + prj.File, prj.Folder.Path + text + ".qlproj");
                Directory.Move(prj.Folder.Path, prj.ParentSolution.HomeFolderPath + text);

                prj.Name = text;
                prj.Folder.Name = text;
                prj.HomeFolderPath = prj.ParentSolution.HomeFolderPath + text + "\\";
                SolutionManager.Instance.SaveSolution();
                #endregion
            }
            else if (e.Node.Tag is QLabFolder)
            {
                #region Edit Folder Name
                if (!PathHelper.Instance.IsRegularFilePath(text))
                {
                    e.CancelEdit = true;
                    e.Node.Text = (e.Node.Tag as QLabFolder).Name;
                    return;
                }

                QLabFolder folder = e.Node.Tag as QLabFolder;
                if (text == folder.Name || folder.ParentFolder.QLabFolders.ContainsKey(text)
                    || folder.ParentFolder.QLabFiles.ContainsKey(text)) return;

                Directory.Move(folder.Path, folder.ParentFolder.Path + text + "\\");
                folder.Name = text;
                SolutionManager.Instance.SaveSolution();
                #endregion
            }
            else if (e.Node.Tag is QLabFunction)
            {
                #region Edit File Name
                if (!PathHelper.Instance.IsRegularFileName(text))
                {
                    e.CancelEdit = true;
                    e.Node.Text = (e.Node.Tag as QLabFunction).Name;
                    return;
                }

                if (!text.EndsWith(".f"))
                    text = text + ".f";

                e.Node.Text = text;
                e.CancelEdit = true;

                treeViewSolution.Invalidate();
                QLabFunction file = e.Node.Tag as QLabFunction;
                if (text == file.Name || file.ParentFolder.QLabFolders.ContainsKey(text)
                    || file.ParentFolder.QLabFiles.ContainsKey(text)) return;

                File.Move(file.Path, file.ParentFolder.Path + text);
                file.Name = text;
                SolutionManager.Instance.SaveSolution();
                #endregion
            }
        }

        private void treeViewSolution_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                TreeViewHitTestInfo hti = this.treeViewSolution.HitTest(e.Location);
                if (hti.Node != null)
                    treeViewSolution.SelectedNode = hti.Node;
            }
        }

        private void treeViewSolution_KeyDown(object sender, KeyEventArgs e)
        {
            if (treeViewSolution.SelectedNode == null)
                return;
            if (e.KeyCode == Keys.F2)
                treeViewSolution.SelectedNode.BeginEdit();
        }

        private void treeViewSolution_DoubleClick(object sender, EventArgs e)
        {
            if (this.treeViewSolution.SelectedNode == null ||
                !(this.treeViewSolution.SelectedNode.Tag is QLabFunction))
                return;

            OnFunctionOpen(this.treeViewSolution.SelectedNode.Tag as QLabFunction);
        }

        public delegate void FunctionOpenedDelegate(object sender, FunctionOpenedEventArgs e);
        public event FunctionOpenedDelegate FunctionOpened = null;
        private void OnFunctionOpen(QLabFunction file)
        {
            if (this.FunctionOpened != null)
                this.FunctionOpened(this, new FunctionOpenedEventArgs(file));
        }
    }

    public class FunctionOpenedEventArgs : EventArgs
    {
        private QLabFunction function;
        public QLabFunction Function
        {
            get { return this.function; }
        }

        public FunctionOpenedEventArgs(QLabFunction function)
        {
            this.function = function;
        }
    }
}